package com.zyl.queue;

import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

/**
 * @author zhaoyl
 * @date 2024/5/16 21:56
 * @description 说明
 * SynchronousQueue的优点在于其直接性和高效性，它实现了线程间的即时数据交换，无需中间缓存，
 * 确保了数据传输的实时性和准确性，同时，其灵活的阻塞机制使得线程同步变得简单而直观，适用于需要精确协调的生产者-消费者模型。
 *SynchronousQueue类在Java中主要用于解决线程间的直接、同步的数据交换问题
 * 案例：
 * 假如，有一个在线购物平台，其中有一个非常关键的部分是处理用户的支付请求，当用户点击“支付”按钮后，系统需要确保用户的支付请求能够被安全、
 * 快速地处理，并且一旦处理完成，能够立即通知用户支付结果。
 * 在这个场景中，可以将SynchronousQueue看作是一个没有容量的阻塞队列，它严格遵循FIFO（先进先出）的原则，但特殊的是，它不会保存任何元素，
 * 而是直接在不同的线程间进行传递。
 * 当用户提交支付请求时，可以创建一个线程（或者使用一个线程池中的线程），该线程负责处理支付逻辑，这个线程会尝试将支付请求放入SynchronousQueue中，
 * 但是，由于SynchronousQueue没有容量，这个线程将会被阻塞，直到有另一个线程从队列中取出这个支付请求。
 * 同时，还需有一个或多个线程负责处理支付结果，这些线程会不断地从SynchronousQueue中尝试取出支付请求进行处理，一旦取到支付请求，
 * 它们就会开始处理，并将处理结果返回给用户。

 */
public class SynchronousQueueDemo {
    public static void main(String[] args) throws InterruptedException {
        // 创建一个SynchronousQueue实例
        SynchronousQueue<Integer> queue = new SynchronousQueue<>();

        // 创建一个生产者线程
        Thread producerThread = new Thread(() -> {
            try {
                // 模拟生产数据的过程
                TimeUnit.SECONDS.sleep(1);
                int data = 100; // 假设这是生产的数据

                // 将数据放入SynchronousQueue中，如果此时没有消费者线程等待，生产者线程将会被阻塞
                queue.put(data);
                System.out.println("生产者线程: 数据 " + data + " 已被放入队列。");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // 创建一个消费者线程
        Thread consumerThread = new Thread(() -> {
            try {
                // 从SynchronousQueue中取出数据，如果没有数据可取，消费者线程将会被阻塞
                int data = queue.take();

                // 模拟消费数据的过程
                TimeUnit.SECONDS.sleep(1);
                System.out.println("消费者线程: 数据 " + data + " 已被消费。");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // 启动生产者和消费者线程
        producerThread.start();
        consumerThread.start();
        // 等待两个线程执行完毕
        producerThread.join();
        consumerThread.join();

        System.out.println("主线程: 程序执行完毕。");
    }
}
